#ifndef _AGB_SYS_H_
#define _AGB_SYS_H_

#include "agbmusic.h"

/*
新的处理程序
*/

const u8 clock_tbl[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE
,0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
,0x18, 0x1C, 0x1E, 0x20, 0x24, 0x28, 0x2A, 0x2C, 0x30
,0x34, 0x36, 0x38, 0x3C, 0x40, 0x42, 0x44, 0x48, 0x4C
,0x4E, 0x50, 0x54, 0x58, 0x5A, 0x5C, 0x60, 0, 0, 0
};


//转换成AGB的频率
static int freq2agb(int freq,int midkey){
    midkey = 180 - midkey;
    double v = (double)midkey / 12.0;
    return (freq * pow(2.f,v))+0x5;
}

//agb转成默认频率
static int agb2freq(int freq,int key){
    double m = (double)(180 - key) / (double)12;
    m = pow(2,m);
    freq = ((double)freq / m) + 0.5;
    return freq;
}

static int _MidiKey2Freq(int freq,u32 midkey,u32 fp){
    double tmp;
    tmp = ((double)(180 - midkey)) - ((double)fp / 256.f);
    tmp = pow((double)2.f, tmp / 12.f);
    return (int)((double)freq / tmp);
}

//BIOS实现
static int MidiKey2Freq(WaveData*w,u32 midkey,u32 fp){
    int freq = (int)w->freq;
    double tmp;
    tmp = ((double)(180 - midkey)) - ((double)fp / 256.f);
    tmp = pow((double)2.f, tmp / 12.f);
    return (int)((double)freq / tmp);
}
#define M_LN2 0.69314718055994530942
//把c5速度转换成relnote
static void c5speed_relnote(int freq,uint8_t *note,uint8_t *fine){
    if(!freq){
        *note = 0;
        *fine = 0;
        return;
    }
    int v = log(freq * (1.0/8363.0))* (12.0 * 128.0 * (1.0 / M_LN2));
    *note = v/128;
    *fine = v&0x7f;
}

static int relnote_c5speed(int note,int fine){
    double v = round(pow(2.0, (note * 128.0 + fine) * (1.0 / (12.0 * 128.0))) * 8363.0);
    if(v>UINT32_MAX) return UINT32_MAX;
    if(v<0) return 0;
    return v;
}

static int c5_note_freq(int freq,int note){
    note -= xm_Cn5;
    freq *= pow(2.0,((double)note / 12.0));
    return freq;
}


/* E:\programfiles\AGB\MusicPlayerAGB2000\mp2000\b.gba (2014/12/19 18:16:00)
   起始位置(h): 00003BEC, 结束位置(h): 00003C9F, 长度(h): 000000B4 */

static unsigned char ScaleTable[180] = {
	0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
	0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
	0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
	0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB,
	0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB,
	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B,
	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B,
	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
};

static const u32 FreqTable[] = {
0x80000000, 0x879C7C97, 0x8FACD61E, 0x9837F052, 0xA14517CC,
0xAADC0848, 0xB504F334, 0xBFC886BB, 0xCB2FF52A, 0xD744FCCB,
0xE411F03A, 0xF1A1BF39
};

static u32 _key2fr(u32 a1,u32 a2){
    return (u64)a1*(u64)a2 >> 32;
}
//内置软件实现
static int MidiKey2fr(WaveData*w,u32 midkey,u32 fp){
    int freq = (int)w->freq;
    fp <<= 24;
    if(midkey>0xb2){
        midkey = 0xb2;
        fp = 0xFF000000;
    }
    int freq1 = FreqTable[ScaleTable[midkey]&0xf]>>(ScaleTable[midkey]>>4);
    int freq2 = FreqTable[ScaleTable[midkey+1]&0xf]>>(ScaleTable[midkey+1]>>4);
    return _key2fr(freq,(freq1 + _key2fr((freq2-freq1),fp)));
}


unsigned char rawData[26] = {
	0x00, 0xB5, 0x00, 0x04, 0x07, 0x4A, 0x08, 0x49, 0x40, 0x0B, 0x40, 0x18,
	0x83, 0x88, 0x59, 0x00, 0xC9, 0x18, 0x89, 0x00, 0x89, 0x18, 0x0A, 0x68,
	0x01, 0x68
};
static u8 *rom = 0;
static u32 find_rom(){
    int i=0;
    int ci = 0;
    for(i=0;i<1024*1024*32;i++){
        for(ci=0;ci<sizeof(rawData);ci++){
            if(rom[i+ci]!=rawData[ci]){
                /*不相等*/
                break;
            }
        }
        if(ci==sizeof(rawData)){
            //全部相等
            return i + 0x08000000;
        }
    }
    return 0;
}

static u8*rom_data(const char*path){
    FILE*file = fopen(path,"rb");
    if(!file)return 0;
    fseek(file,0,SEEK_END);
    int sz = ftell(file);
    fseek(file,0,SEEK_SET);
    u8 *data = (u8*)calloc(1,1024*1024*32);  //32MB
    fread(data,sz,1,file);
    fclose(file);
    return data;
}

static void* fix_rom(void*data){
    s32 dp = (s32)data; /*把0x08000000修复成rom的地址*/
    dp -= 0x08000000;
    if(dp>=0&&dp<1024*1024*32){
        return rom + dp;
    }
    return 0;
}

static double row_per_second(int agb_tempo){
    agb_tempo *= 2;
    double v = (double)150/ (double)agb_tempo; //多少帧执行一个节拍
    v = 60/v;                            //一秒多少节拍
    return v;
}

#define fix_rom(v) fix_rom((void*)(v))

#endif